var logger = require("../utils/log");

var socketMgr = require("./socket_service");
var roomMgr = require("./roommgr");
var redis = require("../utils/redis");

var games = {};
var gamesSeats = {};

var isTiming = false;
var interval = null;

const PERIOD_IDLE_0 = 0; //空闲状态
const PERIOD_FAPAI_1 = 1; //发牌阶段 开始下注
const PERIOD_XIAZHU_4 = 4; //停止下注 开始开牌
const PERIOD_SCORE_5 = 5; //开牌完成 通知积分
const PERIOD_DISSOLVE_99 = 99; //正在解散

// const PERIOD_NOTIFY_HOLD_2 = 2; //发手牌
// const PERIOD_TOZHUANG_3 = 3; //抢庄
// const PERIOD_NOTIFY_ZHUANG_4 = 4; //通知庄
// const PERIOD_NOTIFY_HOLDMORE_6 = 6; //补手牌
// const PERIOD_SCORE_8 = 8; //积分

//初始化数据
function setupGame(room) {
    //牌局共享的数据 包括状态 顺序 出牌
    var game = {
        room:room,
        numOfGames:-1,
        type:room.conf.type,
        roomNo:room.roomNo,
    };
    game.plays = room.players.length;//玩家数量 默认是4 也可以是3
    game.gameSeats = new Array(game.plays);//座位信息

    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i] = {};

        seat.game = game;
        seat.seatIndex = i;//0 1 2 3
        seat.userId = room.players[i].userId;

        gamesSeats[seat.userId] = seat;
    }

    games[room.roomNo] = game;
    refreshGame(game);

    return game;
};

function refreshGame(game) {
    game.memberOfAgree = 0;//同意的人数
    game.memberOfRefuse = 0;//拒绝的人数
    game.paiLength = 52;//牌的长度 蚌埠麻将200张字
    game.pkPais = null;//麻将牌
    game.state = PERIOD_IDLE_0;//0准备下一局  999正在请求解散
    game.turn = 0;//当前轮到谁
    game.index = 0;//牌的下标
    game.zhuang = null;
    game.zhuangBei = 0;

    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        //是否开牌
        seat.niuX = -1;
        //持有的牌
        seat.holds = [];
    }
    game.numOfGames++;
};

function xiPai() {
    var pkPais = new Array(games.paiLength);

    //40-52黑桃 27-39红桃 14-26梅花 1-13方块
    var index = 0;
    for (var i = 1; i < 53; i++) {
        pkPais[index] = i;
        index++;
    }

    //乱序
    for (var i = 0; i < 52; i++) {
        var lastIndex = 51-i;
        var index = Math.floor(Math.random() * lastIndex);
        var t = pkPais[index];
        pkPais[index] = pkPais[lastIndex];
        pkPais[lastIndex] = t;
    }

    games.pkPais = pkPais;
};

function faPai(game) {
    var bupai = game.type == 13; //13表示是明牌抢庄
    var length = bupai ? 4*game.plays : 5*game.plays;
    for (var i = 0; i < length; i++) {
        moPai(game);
        moveToNextUser(game);
    }

    //通知手牌
    socketMgr.notify_holds(game);
    //进入到抢庄阶段
    game.state = PERIOD_TOZHUANG_3;

    if (bupai) { //补牌阶段
        for (var j = 0; j < game.plays; j++) {
            moBuPai(game);
            moveToNextUser(game);
        }
    }
};

function moPai(game) {
    if (game.index == game.paiLength) return -1;

    var seat = game.gameSeats[game.turn];
    var pai = game.pkPais[game.index];
    seat.holds.push(pai);
    game.index++;

    return pai;
};

function moveToNextUser(game){
    game.turn++;
    game.turn %= game.plays;
    return game.gameSeats[game.turn];
};

//开始牌局 房主才可以
function beginGame(userId, roomNo) {
    if (!roomMgr.isCreator(roomNo, userId)) return;
    var room = roomMgr.getRoomByRoomNo(roomNo);
    if(room == null) {
        logger.error("begin error", roomNo);
        return;
    }

    setupGame(room);

    if (isTiming) return;
    isTiming = true;
    startTimer();
};

//开启定时器
function startTimer() {
    interval = setInterval(function () {
        for (var roomNo in games) {
            var game = games[roomNo];
            if (game == null) continue;
            game.count++;

            if (game.count == PERIOD_FAPAI_1) { //发牌阶段 准备下注
                logger.debug('---------runloop--------' + roomNo);
                xiPai(game);
                faPai(game);
                socketMgr.notify_holds(game);
                game.state = PERIOD_FAPAI_1;
            } else if (game.count == PERIOD_XIAZHU_4) { //开牌阶段
                logger.debug('---------runloop--------' + roomNo);
                game.state = PERIOD_FAPAI_1;
                openPai(game);
            } else if (game.count == PERIOD_SCORE_5) { //比牌统计分数
                logger.debug('---------runloop--------' + roomNo);
                game.state = PERIOD_SCORE_5;
                biPai(game);
                calcScore(game);
                game.count = 0;
            }
        }

        if (Object.keys(games).length < 1) {
            clearInterval(interval);
            interval = null;
            isTiming = false;
        }
    }, 5000); //每s秒循环一次
};

//自动开牌
function openPai(game) {
    //有人没亮牌
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        if (seat.niuX < 0) {
            seat.holds.sort(function (a, b) {
                return b - a; //从大到小
            });
            seat.niuX = suanNiu(seat.holds);
            //通知牛几
            socketMgr.notify_niu(seat);
        }
    }
};

//比牌
function biPai(game) {
    var paiResultInfoArr = [];
    for (var i = 0; i < 3; i++) {
        var holds = game.paiInfo[i];
        var niuX = 0;
        if (game.type == 1) { //牛牛
            niuX = suanNiu(holds);
        } else {
            niuX = suanJinhua(holds,game,i); //现在holds是处理过的数据
        }
        var niuResult = {
            niuX:niuX,
            holds:game.paiInfo[i],
            stableHolds:game.paiStableInfo[i],
            p:i,
        };
        paiResultInfoArr.push(niuResult);
    }
    game.paiResultInfo = paiResultInfoArr;

    if (game.type == 1) { //牛牛
        paiResultInfoArr.sort(function (a, b) {
            if (a.niuX == b.niuX) { //牛同样的牛
                a.holds.sort(function (c, d) {
                    return d -c; //从大到小
                });
                b.holds.sort(function (c, d) {
                    return d - c; //从大到小
                });
                return b.holds[0] - a.holds[0];//从大到小
            } else {
                return b.niuX - a.niuX;//从大到小
            }
        });
    } else if (game.type == 2){
        paiResultInfoArr.sort(function (a, b) {
            if (a.niuX == b.niuX) { //同样的牌型
                logger.debug('---------a.niuX == b.niuX--------a.holds--------'+ a.holds);
                logger.debug('---------a.niuX == b.niuX--------b.holds--------'+ b.holds);

                if (b.holds[0] == a.holds[0]) {
                    if (b.holds[1] == a.holds[1]) {
                        if (b.holds[2] == a.holds[2]) {
                            return 1;//从大到小
                        } else {
                            return b.holds[2] - a.holds[2];//从大到小
                        }
                    } else {
                        return b.holds[1] - a.holds[1];//从大到小
                    }
                } else {
                    return b.holds[0] - a.holds[0];//从大到小
                }
            } else {
                return b.niuX - a.niuX;//从大到小
            }
        });
    }

    var p = paiResultInfoArr[0].p;
    game.pWin = p;
    // return game.zhuInfo[p];
};

//算积分
function calcScore(game) {
    var seats = new Array(game.plays); //去排序新数组 不影响原来的数组
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        seats[i] = seat;
    }

    seats.sort(function (sa, sb) {
        if (sb.niuX == sa.niuX) { //牛同样的牛
            return sb.holds[0] - sa.holds[0];//从大到小
        } else {
            return sb.niuX - sa.niuX;//从大到小
        }
    });

    var zhuangSeat = null;
    var zhuangScore = 0;
    var zhuangWinIndex = -1;

    var isPlus = true;
    var gameScore = {};

    for (var i = 0; i < game.plays; i++) {
        var seat = seats[i];
        if (seat.userId === game.zhuang) { //庄的位置
            zhuangSeat = seat;
            zhuangWinIndex = i;

            isPlus = false;
            continue;
        }
        var score = suanBeishu(seat.niuX)*game.zhuangBei*seat.xiaZhu;
        if (isPlus) { //庄输
            zhuangScore -= score;
            gameScore[seat.userId] = score;
        } else { //庄赢
            zhuangScore += score;
            gameScore[seat.userId] = -score;
        }
    }

    gameScore[game.zhuang] = zhuangScore;
    game.room.results.push(gameScore);

    //缓存每一局游戏的数据
    var key = redis.redisCacheKey(redis.REDIS_ROOM_RESULT_INFO, game.room.roomNo);
    redis.redisClient.sadd(key, JSON.stringify(gameScore));

    game.room.results.push(gameScore);
    var statistics = game.room.statistics;
    for (var userId in gameScore) {
        var score = statistics[userId];
        if (score) {
            score += gameScore[userId];
        }
        statistics[userId] = score;
    }

    //通知积分
    socketMgr.notify_score(game);

    if (game.numOfGames == game.room.conf.numOfGames) {
        game.state = PERIOD_IDLE_0;
        endGame(game);
    }

    game.state = PERIOD_IDLE_0;
    refreshGame(game);
};

//结束游戏
function endGame(game, force){
    if (!force) { //强制解散已经通知解散结果
        socketMgr.notify_game_end(game);
    }
    //延迟2S 做断开socket 清理room操作
    setTimeout(function () {
        //关闭房间
        roomMgr.closeRoom(game.room.creator, game.room.roomNo);
        //踢出所有房间socket
        socketMgr.konckout_all(game);
        //清楚房间信息
        delGameInfo(game);
    }, 2000);

};

//清除游戏信息
function delGameInfo(game) {
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        delete gamesSeats[seat.userId];
    }
    delete games[game.roomNo];
};

function xiaZhu(userId, zhu, p) {
    // var roomId = roomMgr.getRoomIDByUserID(userId);
    // if (roomId == null) {
    //     return;
    // }
    // var game = games[roomId];
    //
    // var zhuTotal = game.zhuTotalInfo[p];
    // var zhuArr = game.zhuInfo[p];
    //
    // //p位置的下注信息不存在
    // if (zhuArr == null) {
    //     var userZhu = {
    //         userId:userId,
    //         zhu:zhu,
    //     };
    //     var pArr = [];
    //     pArr.push(userZhu);
    //
    //     game.zhuInfo[p] = pArr;
    //
    //     zhuTotal = zhu;
    //     game.zhuTotalInfo[p] = zhuTotal;
    // } else {
    //     var userZhu = null; //用户下注信息
    //
    //     var length = zhuArr.length;
    //     for (var i = 0; i < length; i++) {
    //         var userZhuInfo = zhuArr[i];
    //
    //         //p位置用户下注信息已存在
    //         if (userZhuInfo.userId == userId) {
    //             userZhu = userZhuInfo;
    //             break;
    //         }
    //     }
    //
    //     if (userZhu == null) {
    //         userZhu = {
    //             userId:userId,
    //             zhu:zhu,
    //         };
    //         zhuArr.push(userZhu);
    //     } else {
    //         userZhu.zhu += zhu;
    //     }
    //
    //     //在之前的基础上加一份注
    //     zhuTotal += zhu;
    //     game.zhuTotalInfo[p] = zhuTotal;
    // }
    //
    // var total = {
    //     userId:0,
    //     zhu:zhuTotal,
    // };
    // return [userZhu, total];
};

function suanNiu(holds) {
    //临时pai数组
    var paisArr = new Array(5);
    //特殊牛
    // var paisMap = new Map();

    // var paisMin = 0;
    // var paisMax = 0;
    var paisAll = 0;

    //1-13
    //14-26
    //27-39
    //40-52
    for (var k = 0; k < 5; k++) {
        var pai = holds[k];
        //14--25,26
        pai = pai%13;
        if (pai === 0) {
            pai = 13;
        }
        // var huase = Math.round(random/13);
        // paisMap.set(pai, 1);
        // paisMin += pai;
        if (pai > 10 && pai < 14) {
            // paisMax += 11;
            pai = 10;
        }

        paisAll += pai;

        paisArr.push(pai);
    }
    //炸弹牛
    // if (paisMap.size === 2) {
    //     return 13;
    // }

    //五小牛
    // if (paisMin < 11 && paisMin > 0) {
    //     return 12;
    // }

    //五花牛
    // if (paisMax == 55) {
    //     return 11;
    // }

    //箭头函数 以及 高阶函数示例
    // pais = pais.map((x) => { return k>10 && k<14 ? 10 : k });
    // paisArr = paisArr.sort((a, b) => {return a -b});
    // paisArr = paisArr.sort(a - b);

    paisArr.sort(function(a, b) {
        return b-a;
    });

    //牛 递归算牛
    //4 5 6 7 8
    //456 457 458
    //467 468
    var pai1 = 0;
    var pai2 = 0;
    var pai3 = 0;
    var isNiun = false;
    for (var k = 0; k < 3; k++) { //0 1 2
        for (var i = k+1; i < 4; i++) { // 1 2 3
            for (var j = i+1; j < 5; j++) { //2 3 4
                pai1 = paisArr[k];
                pai2 = paisArr[i];
                pai3 = paisArr[j];
                if ((pai1 + pai2 + pai3)%10 === 0) {
                    isNiun = true;
                    break;
                }
            }
            if (isNiun) {
                break;
            }
        }
        if (isNiun) {
            break;
        }
    }

    if (isNiun) {
        var niux = paisAll%10;
        if (niux === 0) {
            niux = 10;
        }
        return niux;
    }
    return 0;
};

function suanJinhua(holds, game, index) {
    //豹子10
    //同花顺 9
    //同花 8
    //顺子 7
    //对子 6
    //单牌 5
    //235  4
    var paiType = 0;

    //临时pai数组
    var paisArr = [];
    //临时paiMap
    var paisMap = new Map();

    for (var k = 0; k < 3; k++) {
        var pai = holds[k];
        //14--25,26
        pai = pai%13;
        if (pai === 0) { //刚好是K
            pai = 13;
        } else if (pai === 1) { //刚好是A
            pai = 14;
        }

        paisMap.set(pai, 1);
        paisArr.push(pai);
    }

    paisArr.sort(function (a, b) {
        return b - a; //从大到小
    });

    if (paisMap.size == 1) { //是否是豹子
        paiType = 10;
    } else if (paisMap.size == 2) { //是否是对子
        paiType = 6;
    } else {
        var isShunzi = beShunzi(paisArr);
        //算金花 需要最原始的牌 因为%13
        var isTonghua = beTonghua(holds);
        if (isShunzi && isTonghua) {
            paiType = 9;
        } else if (isTonghua) {
            paiType = 8;
        } else if (isShunzi) {
            paiType = 7;
        } else if (be235(paisArr)) {
            paiType = 5;
        } else {
            paiType = 5;
        }
    }
    game.paiInfo[index] = paisArr;
    return paiType;
};

function beTonghua(holds) {
    var isTonghua = false;
    //是否是同花
    var type = getPKType(holds[0]);
    for (var i = 1; i < 3; i++) {
        if (getPKType(holds[i]) == type) { //同一种花色
            isTonghua = true;
        } else {
            isTonghua = false;
            break;
        }
    }
    return isTonghua;
};

function beShunzi(holds) {
    //是否是顺子 AKQ
    var isShunzi = false;
    //是否是同花
    var pai = holds[0];
    for (var i = 1; i < 3; i++) {
        var temp = holds[i];
        if (Math.abs(pai - temp) == 1) { //相差等于1 有成为顺子的机会
            pai = temp;
            isShunzi = true;
        } else {
            isShunzi = false;
            break;
        }
    }
    return isShunzi;
};

function be235(holds) {
    var is235 = false;
    for (var i = 0; i < 3; i++) {
        if (i == 2 && holds[i] == 2) {
            is235 = true;
        } else if (i == 1 && holds[i] == 3) {
            is235 = true;
        } else if (i == 0 && holds[i] == 5) {
            is235 = true;
        } else {
            is235 = false;
            break;
        }
    }
    return is235;
};

function suanBeishu(niuX) {
    var beishu = 1;
    if (niuX < 7) {
        beishu = 1;
    } else if (niuX == 7) {
        beishu = 2;
    } else if (niuX == 8) {
        beishu = 2;
    } else if (niuX == 9) {
        beishu = 3;
    } else if (niuX == 10) {
        beishu = 4;
    } else if (niuX == 11) {
        beishu = 5;
    } else if (niuX == 12) {
        beishu = 6;
    } else if (niuX == 13) {
        beishu = 7;
    }
    return beishu;
};

function getPKType(id) {//黑红梅方
    if(id > 0 && id < 14){ //1-13
        //方
        return 1;
    } else if(id > 13 && id < 27){ //14-26
        //梅
        return 2;
    } else if(id > 26 && id < 40){ //27-39
        //红
        return 3;
    } else if(id > 39 && id < 53){ //40-52
        //黑
        return 4;
    }
};

function randomIndex(num) { //0到x取值
    return Math.floor(Math.random() * num);
};

function gameState(roomNo) {
    var game = games[roomNo];
    if (game == null) return -1;
    return game.state;
};

exports.beginGame = beginGame;
exports.xiaZhu = xiaZhu;
exports.gameState = gameState;



















